#include <stdio.h>
#include <stdlib.h> //exit()
#include <string.h>
#include <errno.h>
#include <unistd.h> //getpid
#include <wsim/websocket_common.h>
#include <pthread.h>
#include <jsoncpp/json/json.h> /*jsoncpp -ljsoncpp*/
#include <iostream>
using namespace std;


char ip[128] = {0};//"172.16.23.160";// 本机IP
int port = 9753;
typedef struct{
    int fd;
    WebsocketData_Type datatype;
    char *buf;
}pthreadArg;

void* thread_fun(void *arge)
{
    pthreadArg *pArg=(pthreadArg*)arge;
    /************************************************************
     *json;
     * stype:类型
     *      hi~ 查看，服务器自回复（Hi~ )
     * message:内容
     * form:来源
     * to:去向
     *
     * *********************************************************/
                Json::Reader reader;
                    Json::Value root;
                    if(reader.parse(pArg->buf,root))//reader将字符串解析到root
                    {
                        if(root["stype"].isNull())
                        {
                            cout<<"无法解析数据！！！"<<endl;
                            pthread_exit((void*)pthread_self()) ;
                        }
                            string stype=root["stype"].asString();//访问节点
                            if(stype.compare("Hi~") == 0)
                            {
                                int sfd=root["fd"].asInt();
                                string sUUID=root["uuid"].asString();
                                string reStr=root["message"].asString();
                                cout<<endl<<endl<<"fd:"<<sfd<<",uuid:"<<sUUID<<endl<<reStr<<endl;
                            }
                            else if(stype.compare("onlineClients")==0)
                            {
                                int lineClient_size=root["arrayUser"].size();
                                cout<<endl<<endl<<"在线用户："<<lineClient_size<<"个"<<endl;
                                for(int i=0;i<lineClient_size;++i)
                                {
                                    int clientfd=root["arrayUser"][i]["fd"].asInt();
                                    string clientnickname=root["arrayUser"][i]["nickname"].asString();
				    string cuuid=root["arrayUser"][i]["uuid"].asString();
                                    cout<<"\t"<<clientnickname<<"["<<clientfd<<":"<<cuuid<<"]"<<endl;
                                }
                            }
			else if(stype.compare("newjoin")==0)
			{
				int join_size=root["arrayUser"].size();
				for(int i=0;i<join_size;++i)
				{
					int nfd=root["arrayUser"][i]["fd"].asInt();
					string nNickname=root["arrayUser"][i]["nickname"].asString();
					string nUUID=root["arrayUser"][i]["uuid"].asString();
                                        cout<<endl<<endl<<"客户上线："<<nNickname<<"["<<nfd<<":"<<nUUID<<"] 。"<<endl;
				}
			}
                            else if(stype.compare("dropline")==0)
                            {
                                    int join_size=root["arrayUser"].size();
                                    for(int i=0;i<join_size;++i)
                                    {
                                            int nfd=root["arrayUser"][i]["fd"].asInt();
                                            string nNickname=root["arrayUser"][i]["nickname"].asString();
					    string nUUID=root["arrayUser"][i]["uuid"].asString();
                                            cout<<endl<<endl<<"客户下线："<<nNickname<<"["<<nfd<<":"<<nUUID<<"] 。"<<endl;
                                    }
                            }
                            else if(stype.compare("message")==0)
                            {
                                string fname=root["form"].asString();
				string fuuid=root["fuuid"].asString();
                                string msg=root["message"].asString();
                                int ffd=root["ffd"].asInt();
                                cout<<endl<<endl<<fname<<"["<<ffd<<"]"<<" 说："<<endl<<msg<<endl<<endl;
                            }
                            else
                                cout<<endl<<endl<<"未处理："<<endl<<pArg->buf<<endl;
                    }

    if(pArg->buf) free(pArg->buf);
    if(pArg) free(pArg);
    pthread_exit(0);
}
/******************************************
 * 响应客户端
 * 参数： fd 句柄
 *       datatype 数据类型
 *       buf 缓存
 *       bufLen 缓存大小
 * 说明：数据接收数据后，请在此对数据进行处理。
******************************************/
int client_callBack(int fd,WebsocketData_Type datatype, char *buf, unsigned int bufLen)
{
    int ret=0;
    if(bufLen > 0)
	{
        /*
		printf("client(fd/%d) recv:\r\n"
            "数据类型：%d\r\n"
            "数据长度byte:%d\r\n"
            "内容：\r\n%s\r\n"
            , fd,datatype,bufLen, buf);		*/        

        char *pthreadBuf=(char*)calloc(bufLen,sizeof(char));
        memcpy(pthreadBuf,buf,bufLen);
        pthreadArg *pArg=(pthreadArg*)calloc(1,sizeof(pthreadArg));
        pArg->fd=fd;
        pArg->datatype=datatype;
        pArg->buf=pthreadBuf;
        pthread_t thread_id;
        if(pthread_create(&thread_id, NULL, thread_fun, (void *)(pArg)) != 0)
	    {
		    printf("创建处理线程失败!\r\n");
		    return -1;
	    } 
	}

	return ret;
}
int client_callCloseed(int fd)
{
    printf("服务器已关闭！！！！%d\r\n",fd);    

    //pthread_cancel(client_thread_id);     // 等待线程关闭

    return 0;
}


int main(int argc,char *argv[])
{
    int ret, timeCount = 0;
    int fd;
    char buff[1024];
    int pid;
    unsigned long int cid;
 
    if(argc<2)
    {
        printf("未输入服务器地址，自动使用127.0.0.1。\r\n");
        sprintf(ip,"127.0.0.1");
    }
    else
        sprintf(ip,"%s",argv[1]);
    //
    pid = getpid();
    printf("\r\n========== client(%d) start ! ==========\r\n\r\n", pid);
    printf("\r\n输入：\r\n");
        printf("\thelp;\t显示帮助。\r\n");
        printf("\tjoin:昵称\t以当前名称登入。\r\n");
        printf("\ttoall;内容\t向所有在线用户发送。\r\n");
        printf("\ttofd:句柄;内容\t向特定用户发送。\r\n");
        printf("\tto:昵称;内容\t特定发送。\r\n");
        printf("\tgetusers;\t获取在线用户。\r\n");
        printf("\texit;\t退出。\r\n");
    //
    //netCheck_getIP("wlp3s0", ip);
    
	
    fd=client_init(ip,port,"/null",(CallBackFun*)&client_callBack,(CallCloseedFun*)&client_callCloseed);
    if(fd <= 0)
    {
        printf("client_init failed !\r\n");
        return -1;
    }   

    
    webSocket_delayms(100);
    memset(buff, 0, sizeof(buff));
    sprintf(buff, "Say hi~ from client(%d)", pid);    
    Json::Value sendRoot;
    sendRoot["stype"]="hi~";
    sendRoot["message"]=buff;
    string sendStr=sendRoot.toStyledString();
    ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
    //登入
    if(argc>2)
    {
        memset(buff,0,sizeof(buff));
        sprintf(buff,"%s",argv[2]);
        sendRoot["stype"]="join";
        sendRoot["message"]=buff;
        string sendStr=sendRoot.toStyledString();
        ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
    }
    //
 
    while(1)
    {     
        cin>>buff;
        if(strlen(buff)>0){
            string inStr=buff;
        if(strstr(buff,"exit;")==buff)
        {
            webSocket_send(fd,buff,strlen(buff),true,WDT_DISCONN);
            close(fd);
            break;
        }
        else if(strstr(buff,"help;")==buff)
        {
        printf("\r\n输入：\r\n");
        printf("\thelp;\t显示帮助。\r\n");
        printf("\tjoin:昵称\t以当前名称登入。\r\n");
        printf("\ttoall;内容\t向所有在线用户发送。\r\n");
        printf("\ttofd:句柄;内容\t向特定用户发送。\r\n");
        printf("\tto:昵称;内容\t特定发送。\r\n");
        printf("\tgetusers;\t获取在线用户。\r\n");
        printf("\texit;\t退出。\r\n");
            continue;
        }
        else if(inStr.compare(0,5,"join:")==0)
        {
            string nickname=inStr.substr(5);
            sendRoot["stype"]="join";
            sendRoot["message"]=nickname;
            string sendStr=sendRoot.toStyledString();
            ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
        }
        else if(inStr.compare(0,9,"getusers;")==0)
        {

            sendRoot["stype"]="getusers";

            string sendStr=sendRoot.toStyledString();
            ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
        }
        else if(inStr.compare(0,6,"toall;")==0)
        {
            sendRoot["stype"]="toall";
            sendRoot["message"]=inStr.substr(6);
            string sendStr=sendRoot.toStyledString();
            ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
        }
        else if(inStr.compare(0,5,"tofd:")==0)
        {
            sendRoot["stype"]="tofd";
            int nameend=inStr.find(";",5);
            if(nameend>4){
                string tname=inStr.substr(5,nameend-5);
                char *end;
            int tfd=    static_cast<int>(strtol(tname.c_str(),&end,10));
            sendRoot["tofd"]=tfd;
            sendRoot["message"]=inStr.substr(nameend+1);
            string sendStr=sendRoot.toStyledString();
            //cout<<sendStr<<endl;
            ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
            }
        }
        else if(inStr.compare(0,3,"to:")==0)
        {
            sendRoot["stype"]="to";
            int nameend=inStr.find(";",3);
            if(nameend>4){
                string tname=inStr.substr(3,nameend-3);

            sendRoot["to"]=tname;
            sendRoot["message"]=inStr.substr(nameend+1);
            string sendStr=sendRoot.toStyledString();
            //cout<<sendStr<<endl;
            ret=webSocket_send(fd,(char*)sendStr.c_str(),sendStr.size(),true,WDT_TXTDATA);
            }
        }
        else{
        webSocket_send(fd, buff, strlen(buff), true, WDT_TXTDATA);
        }
        }
    }
    printf("client close !\r\n");
    return 0;
}

